package com.bw.config;

import com.bw.config.captcha.SecurityCaptchaFilter;
import com.bw.config.security.*;
import com.bw.mapper.SysRoleMenuMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.config.annotation.ObjectPostProcessor;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.HeadersConfigurer;
import org.springframework.security.config.annotation.web.configurers.UrlAuthorizationConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;

import java.util.Collection;
import java.util.LinkedHashMap;

import static org.springframework.security.config.Customizer.withDefaults;

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Autowired
    LoginSuccessHandler loginSuccessHandler;
    @Autowired
    LoginFailHandler loginFailHandler;
    @Autowired
    TokenValidFilter tokenValidFilter;
    @Autowired
    SecurityCaptchaFilter securityCaptchaFilter;

    @Autowired
    SysRoleMenuMapper roleMenuMapper;
    @Autowired
    AuthenticationEntryPointHandler authenticationEntryPointHandler;
    @Autowired
    CustomerAccessDeniedHandler customerAccessDeniedHandler;

    @Autowired
    RoleMenuMetadataSource roleMenuMetadataSource;
    @Autowired
    CustomAccessDecisionManager customAccessDecisionManager;

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
                .csrf().disable() // 禁用csrf验证
                .cors().and() // 跨域
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and() // 禁用session登录
                .formLogin((formLogin) -> formLogin
                        .loginProcessingUrl("/sys/login") //执行登录的URL 这个URL不需要实现，用来给前端form表单使用
                        .usernameParameter("userName") // 定义 登录的入参用户名字段
                        .passwordParameter("password")// 定义 登录的入参密码字段
                        .successHandler(loginSuccessHandler) // 登录成功之后的处理
                        .failureHandler(loginFailHandler) // 登录失败之后的处理
                )
                .authorizeHttpRequests((auth) -> auth
                        .antMatchers(WhiteURLConstant.whiteList.toArray(new String[WhiteURLConstant.whiteList.size()]))
                        .permitAll() // 放开 的URL
//                        .antMatchers("/getAuthMenu","/getAuthRouter").hasRole("base")
                        .anyRequest().authenticated()  //拦截的URL
//                                .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
//                                    @Override
//                                    public <O extends FilterSecurityInterceptor> O postProcess(O object) {
//                                        // 使用配置好的CustomSecurityMetadataSource来代替默认的SecurityMetadataSource对象
//                                        object.setSecurityMetadataSource(roleMenuMetadataSource);
//                                        // 将rejectPublicInvocations设置为true，表示当getAttributes返回null时，不允许访问受保护对象
//                                        object.setRejectPublicInvocations(true);
//                                        object.setAccessDecisionManager(customAccessDecisionManager);
//                                        return object;
//                                    }
//                                })
                )
                .httpBasic(withDefaults());
        ApplicationContext applicationContext = http.getSharedObject(ApplicationContext.class);
        //动态权限配置
        http.apply(new UrlAuthorizationConfigurer<>(applicationContext))
                .withObjectPostProcessor(new ObjectPostProcessor<FilterSecurityInterceptor>() {
                    @Override
                    public <O extends FilterSecurityInterceptor> O postProcess(O object) {
                        // 使用配置好的CustomSecurityMetadataSource来代替默认的SecurityMetadataSource对象
                        object.setSecurityMetadataSource(roleMenuMetadataSource);
                        // 将rejectPublicInvocations设置为true，表示当getAttributes返回null时，不允许访问受保护对象
                        object.setRejectPublicInvocations(true);
                        object.setAccessDecisionManager(customAccessDecisionManager);
                        return object;
                    }
                });
        // 在 校验用户名密码之前 验证token
        http.addFilterBefore(tokenValidFilter, UsernamePasswordAuthenticationFilter.class);
        // 在 校验token之前 验证图片验证码
        http.addFilterBefore(securityCaptchaFilter, TokenValidFilter.class);

        http.exceptionHandling()
                .authenticationEntryPoint(authenticationEntryPointHandler) //用来解决匿名用户访问无权限资源时的异常
                .accessDeniedHandler(customerAccessDeniedHandler); //用来解决认证过的用户访问无权限资源时的异常
        http.removeConfigurer(HeadersConfigurer.class);
        return http.build();
    }


}